package com.suray.wcs.service.plc.util.impl;

import com.suray.basic.wcs.path.core.Lifter;
import com.suray.basic.wcs.path.core.Node;
import com.suray.basic.wcs.path.enums.NodeStatus;
import com.suray.basic.wcs.plc.core.Plc;
import com.suray.basic.wcs.plc.enums.CargoState;
import com.suray.basic.wcs.plc.enums.LifterMode;
import com.suray.basic.wcs.plc.enums.Location;
import com.suray.basic.wcs.plc.pojo.oper.lifter.LifterOper;
import com.suray.basic.wcs.plc.pojo.oper.lifter.TwoDirectionRgvLifterOper;
import com.suray.basic.wcs.plc.utils.PlcUnit;
import com.suray.basic.wcs.utils.Coord;
import com.suray.basic.wcs.utils.LoggerUtil;
import com.suray.commin.core.utils.SpringContextHolder;
import com.suray.wcs.service.core.util.LockNodeManager;
import com.suray.wcs.service.enums.DetailProcess;
import com.suray.wcs.service.enums.PrecessOperation;
import com.suray.wcs.service.enums.PrecessStatus;
import com.suray.wcs.service.enums.ResultEnum;
import com.suray.wcs.service.plc.LifterEvent;
import com.suray.wcs.service.plc.LifterPathNode;
import com.suray.wcs.service.pojo.Rgv;
import com.suray.wcs.service.system.entity.TaskDB;
import com.suray.wcs.service.system.entity.TaskDetailDB;
import com.suray.wcs.service.system.service.impl.NodeDBServiceImpl;
import com.suray.wcs.service.system.service.impl.TaskDetailServiceImpl;
import com.suray.wcs.service.util.WcsUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.HashSet;
import java.util.List;

@Component
public class TwoDirectionRgvLifterEvent extends LifterEvent {
    private final Logger log = LoggerFactory.getLogger(TwoDirectionRgvLifterEvent.class);
    private final NodeDBServiceImpl nodedbServiceImpl = SpringContextHolder.getBean(NodeDBServiceImpl.class);
    private final TaskDetailServiceImpl taskDetailService = SpringContextHolder.getBean(TaskDetailServiceImpl.class);

    @Override
    public void rgvNotLoadAssignHoist1(LifterOper hoistOper, Lifter lifter, Rgv rgv, Integer plcId, int endLayer) throws IOException {
        TwoDirectionRgvLifterOper twoDirectionRgvLifterOper = (TwoDirectionRgvLifterOper) hoistOper;
        long sendTime = System.currentTimeMillis();
        while (!twoDirectionRgvLifterOper.isHasTwoDirectionRgv()) {
            log.info(hoistOper.getDeviceName() + "提升机内没有两向车,四向车模式任务不能执行");
            rgv.checkInterrupt("终止四向车模式任务", sendTime);
            WcsUtil.delay(1000);
        }
        validateAndCall(hoistOper, lifter, rgv, plcId, LifterMode.RGV, 0, Location.INSIDE, endLayer,
                Location.INSIDE);
        validateHoistArrived(hoistOper, endLayer, plcId, rgv);
        twoDirectionRgvLifterOper.lockHoist(rgv.getRgvDB().getRgvNo());
        log.info(hoistOper.getDeviceName() + "上锁成功");
    }

    @Override
    public void rgvNotLoadAssignHoist2(LifterOper hoistOper, Lifter lifter, Rgv rgv, Integer plcId, int endLayer) throws IOException {
        TwoDirectionRgvLifterOper twoDirectionRgvLifterOper = (TwoDirectionRgvLifterOper) hoistOper;
        originalRgvNotLoadAssignHoist2(hoistOper, lifter, rgv, plcId, endLayer);
        twoDirectionRgvLifterOper.lockHoist(rgv.getRgvDB().getRgvNo());
        log.info(hoistOper.getDeviceName() + "上锁成功");
    }

    @Override
    public void palletTask(LifterOper lifterOper, Lifter lifterNode, TaskDB taskdb, Node startNode, int startLayer, int endLayer, Location startLocation, Location endLocation, TaskDetailDB taskDetailDB) throws IOException {
        List<Node> lifterPathStartAndEndNode = LifterPathNode.handleTask(taskdb);
        //写入自卸式提升机有货
        TaskDetailDB writeDet = taskDetailService.buildTask(taskdb.getTaskId(), DetailProcess.WRITE_START_Y, taskDetailDB.getUuid(), taskDetailDB.getStart(), taskDetailDB.getEnding(),
                PrecessStatus.CONDUCT, null, null);
        if (!lifterOper.isPalletExisted(startLayer, startLocation)) {
            PlcUnit.writeTwoDirectionRgvCargoState(lifterOper, startLocation, startLayer, CargoState.HAS_CARGO);
            LoggerUtil.info("写入自卸式提升机起点有货", LifterEvent.class);
        }
        taskDetailService.updateTaskDetailCompleteTime(writeDet);
        while (!lifterOper.isPalletExisted(startLayer, startLocation) || !lifterOper.isReady()
                || (lifterOper.getHoistCurrentTaskNo() != 0) || lifterOper.isPalletExisted(endLayer, endLocation) ||
                nodedbServiceImpl.getNode(lifterPathStartAndEndNode.get(1)).getNodeStatus() == NodeStatus.Y) {
            log.info(lifterOper.getDeviceName() + "提升机起点位置有货?: " + lifterOper.isPalletExisted(startLayer, startLocation) + lifterOper.getDeviceName() +
                    "提升机就绪?: " + lifterOper.isReady() + "提升机有任务?: " + (lifterOper.getHoistCurrentTaskNo() != 0) +
                    "提升机终点位置有货?:" + lifterOper.isPalletExisted(endLayer, endLocation) + "终点货位状态为" +
                    (nodedbServiceImpl.getNode(lifterPathStartAndEndNode.get(1)).getNodeStatus() == NodeStatus.Y));
            Plc.checkPLCInterrupt(taskdb.getTaskId().toString(), "LifterEvent1");
            WcsUtil.delay(1000);
        }
        TaskDetailDB taskDetail = taskDetailService.buildTask(taskdb.getTaskId(), DetailProcess.HOIST_RUN, taskDetailDB.getUuid(), taskDetailDB.getStart(), taskDetailDB.getEnding(),
                PrecessStatus.CONDUCT, null, null);
        int taskNo = taskdb.getPlcId();
        TwoDirectionRgvLifterOper twoDirectionRgvLifterOper = (TwoDirectionRgvLifterOper) lifterOper;
        Integer code = validateAndCall(lifterOper, lifterNode, taskdb, taskNo, LifterMode.TWO_DIRECTION_RGV, startLayer, startLocation,
                endLayer, endLocation);
        taskDetail.setRemark(code.toString());
        taskDetailService.updateById(taskDetail);
        while (true) {
            errorValidate(lifterOper);
            if (!twoDirectionRgvLifterOper.isPalletExisted(startLayer, startLocation)) {
                TaskDetailDB startDet = taskDetailService.buildTask(taskdb.getTaskId(), DetailProcess.HOIST_UPDATE_N, taskDetail.getUuid(), taskDetail.getStart(), taskDetail.getEnding(),
                        PrecessStatus.CONDUCT, lifterPathStartAndEndNode.get(0).toString(), PrecessOperation.UPDATE_N.getValue().toString());
                nodedbServiceImpl.updateNodeDBStatus(lifterPathStartAndEndNode.get(0), NodeStatus.N.toString());
                taskDetailService.updateTaskDetailCompleteTime(startDet);
                //起点取货完成解锁起点坐标
                Node node = lifterPathStartAndEndNode.get(0);
                HashSet<Coord> nodes = new HashSet<>();
                nodes.add(node);
                LockNodeManager.unlockedNodes(nodes,taskdb);
                break;
            }
            log.info("等待提升机到达起点移货");
            Plc.checkPLCInterrupt(taskdb.getTaskId() + "", "提升机任务中断");
            WcsUtil.delay(1000);
        }
        while (true) {
            errorValidate(lifterOper);
            if (twoDirectionRgvLifterOper.isPalletExisted(endLayer, endLocation)) {
                nodedbServiceImpl.updateNodeDBStatus(lifterPathStartAndEndNode.get(1), NodeStatus.Y.toString());
                //放货完成锁定终点坐标
                Node node = lifterPathStartAndEndNode.get(1);
                HashSet<Coord> nodes = new HashSet<>();
                nodes.add(node);
                LockNodeManager.unlockedNodes(nodes,taskdb);
                break;
            }
            log.info("等待提升机移库完成");
            Plc.checkPLCInterrupt(taskdb.getTaskId() + "", "提升机任务中断");
            WcsUtil.delay(1000);
        }
        checkHoistTaskFinish(lifterOper, taskNo, endLayer, taskdb);
        log.info(lifterOper.getDeviceName() + "自卸式提升机移货完成" + taskNo);
        TaskDetailDB clearDet = taskDetailService.buildTask(taskdb.getTaskId(), DetailProcess.CLEAR_HOIST_TASK, taskDetail.getUuid(), taskDetail.getStart(), taskDetail.getEnding(),
                PrecessStatus.CONDUCT, null, null);
        twoDirectionRgvLifterOper.setHoistFinalTaskNoClear();
        LifterEvent.liftWord.remove(twoDirectionRgvLifterOper.getLockLocation().toString());
        taskDetailService.updateTaskDetailCompleteTime(clearDet);
        TaskDetailDB unlockDet = taskDetailService.buildTask(taskdb.getTaskId(), DetailProcess.UNLOCK_HOIST_CONNECTION, taskDetail.getUuid(), taskDetail.getStart(), taskDetail.getEnding(),
                PrecessStatus.CONDUCT, null, null);
        LifterPathNode.taskAfter(taskdb);
        taskDetailService.updateTaskDetailCompleteTime(unlockDet);
        taskDetailService.updateTaskDetailCompleteTime(taskDetail);
    }

    @Override
    public Integer validateAndCall(LifterOper hoistOper, Lifter lifter, Object obj, int taskNo, LifterMode lifterMode, int objFloor1, Location objLocation1, int objFloor2, Location objLocation2) throws IOException {
        // 最大值为99
        Integer code = validateParams(hoistOper, lifterMode, objFloor1, objFloor2, objLocation1, objLocation2, obj);
        hoistOper.callLift(code, taskNo);
        LifterEvent.liftWord.put(hoistOper.getLockLocation().toString(), code);
        log.info("调用提升机任务字：" + code + "任务编号" + taskNo);
        return code;
    }

    @Override
    public void validateHoistArrived(LifterOper hoistOper, int endLayer, int taskNo, Rgv rgv) {
        TwoDirectionRgvLifterOper twoDirectionRgvLifterOper = (TwoDirectionRgvLifterOper) hoistOper;
        long sendTime = System.currentTimeMillis();
        log.info(hoistOper.getDeviceName() + "提升机是否到四向车层?: " + hoistOper.isArrived() + ", 当前层: "
                + hoistOper.getHoistCurrentLayer() + ", 需求到达层: " + endLayer + ", 需求完成编号:" + taskNo);
        while (!twoDirectionRgvLifterOper.isArrived() || twoDirectionRgvLifterOper.getHoistCurrentLayer() != endLayer || twoDirectionRgvLifterOper.getHoistFinalTaskNo() != taskNo) {
            log.info(" 等待提升机到达四向车层");
            rgv.checkInterrupt("LifterEvent3", sendTime);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void errorValidate(LifterOper hoistOper) {
        errorOriginalValidate(hoistOper);
        TwoDirectionRgvLifterOper twoDirectionRgvLifterOper = (TwoDirectionRgvLifterOper) hoistOper;
        if (twoDirectionRgvLifterOper.isTwoDirectionRgvFontLimited()) {
            log.error(ResultEnum.提升机两向车前限位超限.toString());
        }
        if (twoDirectionRgvLifterOper.isTwoDirectionRgvBackLimited()) {
            log.error(ResultEnum.提升机两向车后限位超限.toString());
        }
        if (twoDirectionRgvLifterOper.oneDirectionGetCargoHasRgv()) {
            log.error(ResultEnum.一方向取货有四向车.toString());
        }
        if (twoDirectionRgvLifterOper.threeDirectionGetCargoHasRgv()) {
            log.error(ResultEnum.三方向取货有四向车.toString());

        }
        if (twoDirectionRgvLifterOper.oneDirectionGetNoPallet()) {
            log.error(ResultEnum.一方向取货无托盘.toString());
        }
        if (twoDirectionRgvLifterOper.threeDirectionGetNoPallet()) {
            log.error(ResultEnum.三方向取货无托盘.toString());
        }
        if (twoDirectionRgvLifterOper.oneDirectionPutCargoHasRgv()) {
            log.error(ResultEnum.一方向放货有四向车.toString());
        }
        if (twoDirectionRgvLifterOper.threeDirectionPutHasRgv()) {
            log.error(ResultEnum.三方向放货有四向车.toString());
        }
        if (twoDirectionRgvLifterOper.oneDirectionPutCargoHasPallet()) {
            log.error(ResultEnum.一方向放货有托盘.toString());
        }
        if (twoDirectionRgvLifterOper.threeDirectionPutHasPallet()) {
            log.error(ResultEnum.三方向放货有托盘.toString());
        }
        if (twoDirectionRgvLifterOper.isHoistFontLimited()) {
            log.error(ResultEnum.提升机四向车前限位超限.toString());
        }
        if (twoDirectionRgvLifterOper.isHoistBackLimited()) {
            log.error(ResultEnum.提升机四向车后限位超限.toString());
        }
        if (twoDirectionRgvLifterOper.isHoistUpLimited()) {
            log.error(ResultEnum.提升机上限位超限.toString());
        }
        if (twoDirectionRgvLifterOper.isHoistDownLimited()) {
            log.error(ResultEnum.提升机下限位超限.toString());
        }
        if (twoDirectionRgvLifterOper.isHoistBarReadCorrect()) {
            log.error(ResultEnum.扫码读取故障.toString());
        }
        if (twoDirectionRgvLifterOper.isHoistBarRangeCorrect()) {
            log.error(ResultEnum.扫码数值范围错误.toString());
        }
        if (twoDirectionRgvLifterOper.isAlarm()) {
            log.error(ResultEnum.伺服报警.toString());
        }
    }
}
